﻿namespace NTLib.Core.Configuration.Attributes
{
    using Exceptions.Configuration;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using NTLib.Core.Reflection;
    using Values;
    using System.Threading;

    /// <summary>
    /// This attribute will look into the current assembly by default or in the assembly pass in context to create configuration values
    /// using the attribute <seealso cref="TypeExportConfigurationAttribute"/>
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    public class TypeImportConfigurationAttribute : BaseConfigurationAttribute
    {
        #region Properties

        /// <summary>
        /// Gets or sets the type of import. This type will match the ExportType from the attribute <seealso cref="TypeExportConfigurationAttribute"/>
        /// </summary>
        /// <value>
        /// The type of the export.
        /// </value>
        public Type ImportType { get; private set; }

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="TypeImportConfigurationAttribute"/> class.
        /// </summary>
        public TypeImportConfigurationAttribute(Type importType)
        {
            this.ImportType = importType;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Collects the configuration value.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="host"></param>
        /// <param name="token"></param>
        /// <returns>
        /// Return the collection of value extract from the describe process
        /// </returns>
        public override ConfigurationCollection CollectConfigurationValue(Type host, object context = null, CancellationToken token = default(CancellationToken))
        {
            token.ThrowIfCancellationRequested();

            Assembly ass = null;
            if (context != null)
            {
                if (context is Assembly)
                    ass = context as Assembly;
                //else
                // TODO : LOG WARNING
            }

            if (ass == null)
            {
                if (host == null)
                    throw new BadParameterConfigurationException(nameof(host), typeof(Type).Name);

                ass = host.GetTypeInfo().Assembly;
            }

            token.ThrowIfCancellationRequested();

            return new ConfigurationCollection((from type in ass.ExportedTypes
                                                let attr = (from att in type.GetTypeInfo().GetCustomAttributes<TypeExportConfigurationAttribute>()
                                                            where att.ExportType == ImportType
                                                            select att).FirstOrDefault()
                                                where attr != null
                                                select new TypeConfig(attr.Key, type)));

        }

        #endregion
    }
}
